#include "threadPool.h"
// #include "login.h"
#include "loginRegister.h"
#include "file_op.h"

int response(train_t *pResponse, int netfd, char *msg)
{
    send(netfd, &pResponse->type, sizeof(pResponse->type), MSG_NOSIGNAL);
    pResponse->length = strlen(msg);
    memcpy(pResponse->value, msg, pResponse->length);
    send(netfd, &pResponse->length, sizeof(pResponse->length), MSG_NOSIGNAL);
    send(netfd, &pResponse->value, pResponse->length, MSG_NOSIGNAL);
    return 0;
}

void *threadWorker(void *arg)
{
    threadPool_t *pThreadPool = (threadPool_t *)arg;

    // 数据库连接
    pthread_mutex_lock(&pThreadPool->mutex);
    MYSQL *mysql = mysql_init(NULL);
    pthread_mutex_unlock(&pThreadPool->mutex);
    if (mysql == NULL)
    {
        LOG_INFO(pThreadPool->log_fd, LOG_ERROR, "mysql_init failed. %s", mysql_error(mysql));
        exit(EXIT_FAILURE);
    }
    if (mysql_real_connect(mysql, "localhost", "root", "123456", "netdisk", 0, NULL, 0) == NULL)
    {
        pthread_mutex_lock(&pThreadPool->mutex);
        LOG_INFO(pThreadPool->log_fd, LOG_ERROR, "mysql_real_connect failed. %s", mysql_error(mysql));
        pthread_mutex_unlock(&pThreadPool->mutex);
        mysql_close(mysql);
        exit(EXIT_FAILURE);
    }
    else
    {
        pthread_mutex_lock(&pThreadPool->mutex);
        LOG_INFO(pThreadPool->log_fd, LOG_DEFAULT, "mysql_real_connect successful.");
        pthread_mutex_unlock(&pThreadPool->mutex);
    }

    while (1)
    {
        pthread_mutex_lock(&pThreadPool->mutex);
        while (pThreadPool->exitFlag == 0 && pThreadPool->taskQueue.queueSize == 0)
        {
            pthread_cond_wait(&pThreadPool->cond, &pThreadPool->mutex);
        }
        if (pThreadPool->exitFlag == 1)
        {
            pthread_mutex_unlock(&pThreadPool->mutex);
            // 数据库退出
            mysql_close(mysql);
            printf("workerTherad exit.\n");
            pthread_exit(NULL);
        }
        int netfd = pThreadPool->taskQueue.head->netfd;
        deQueue(&pThreadPool->taskQueue);
        pthread_mutex_unlock(&pThreadPool->mutex);
        printf("workerThread got netfd = %d\n", netfd);
        
        UsrInfo_t UsrInfo;  //创建用户信息结构体

        // 用户登录或注册
        while(1)
        {
            train_t *user_sign = (train_t *)calloc(1, sizeof(train_t));
            recv(netfd, &user_sign->type, sizeof(user_sign->type), MSG_WAITALL);
            if (user_sign->type == CMD_SIGNIN) // 登录
            {
                int ret = user_login(netfd, mysql, pThreadPool,&UsrInfo);
                // int ret = sign_in(netfd, mysql, pThreadPool，&UsrInfo);
                if(ret == 0)
                {
                    free(user_sign);
                    break;
                }
            }
            else if (user_sign->type == CMD_SIGNUP) // 注册
            {
                int ret = user_register(netfd, mysql, pThreadPool,&UsrInfo);
                // int ret = sign_up(netfd, mysql, pThreadPool,&UsrInfo);
                if(ret == 0)
                {
                    free(user_sign);
                    break;
                }
            }   
        }
        //准备接收响应信息
        char ret_msg[4096] = {0};
        // business begin
        while (1)
        {
            bzero(ret_msg,sizeof(ret_msg));
            train_t train;
            train_t response_msg;
            memset(&train, 0, sizeof(train));
            ssize_t ret = recv(netfd, &train.type, sizeof(train.type), MSG_WAITALL);
            if (ret == 0 || train.type == CMD_EXIT)
            {
                break;
            }
            recv(netfd, &train.length, sizeof(train.length), MSG_WAITALL);
            if (train.length != 0)
            {
                recv(netfd, train.value, train.length, MSG_WAITALL);
            }
            switch (train.type)
            {
            case CMD_CD:
                printf("cd %s\n", train.value);
                pthread_mutex_lock(&pThreadPool->mutex);
                LOG_INFO(pThreadPool->log_fd, LOG_OPERATION, "user: %s opreation: cd %s", UsrInfo.usr_name, train.value);
                pthread_mutex_unlock(&pThreadPool->mutex);
                ret = cmd_cd(&UsrInfo,train.value,mysql,ret_msg,sizeof(ret_msg));
                if(ret == 0){
                    response_msg.type = RESPON_OK;
                    response(&response_msg, netfd, ret_msg);
                    printf("finish cd.\n");
                }
                else
                {
                    printf("cd failed!\n");
                    pthread_mutex_lock(&pThreadPool->mutex);
                    LOG_INFO(pThreadPool->log_fd, LOG_ERROR, "user: %s opreation error: cd %s failed", UsrInfo.usr_name, train.value);
                    pthread_mutex_unlock(&pThreadPool->mutex);
                    response_msg.type = RESPON_ERROR;
                    response(&response_msg, netfd, "cd failed!");
                }
                break;
            case CMD_LS:
                printf("cmd_ls\n");
                pthread_mutex_lock(&pThreadPool->mutex);
                LOG_INFO(pThreadPool->log_fd, LOG_OPERATION, "user: %s opreation: ls %s", UsrInfo.usr_name, train.value);
                pthread_mutex_unlock(&pThreadPool->mutex);
                ret = cmd_ls(&UsrInfo,ret_msg,sizeof(ret_msg),mysql);
                if(ret == 0)
                {
                    response_msg.type = RESPON_OK;
                    response(&response_msg, netfd, ret_msg);
                    printf("finish ls.\n");
                }
                else
                {
                    printf("ls failed!\n");
                    pthread_mutex_lock(&pThreadPool->mutex);
                    LOG_INFO(pThreadPool->log_fd, LOG_ERROR, "user: %s opreation error: ls failed", UsrInfo.usr_name);
                    pthread_mutex_unlock(&pThreadPool->mutex);
                    response_msg.type = RESPON_ERROR;
                    response(&response_msg, netfd, "ls failed!");
                }
                break;
            case CMD_PWD:
                printf("cmd_pwd\n");
                pthread_mutex_lock(&pThreadPool->mutex);
                LOG_INFO(pThreadPool->log_fd, LOG_OPERATION, "user: %s opreation: pwd", UsrInfo.usr_name);
                pthread_mutex_unlock(&pThreadPool->mutex);
                ret = cmd_pwd(&UsrInfo,ret_msg);
                if(ret == 0)
                {
                    response_msg.type = RESPON_OK;
                    response(&response_msg, netfd, ret_msg);
                    printf("finish pwd.\n");
                }
                else
                {
                    printf("pwd failed!\n");
                    pthread_mutex_lock(&pThreadPool->mutex);
                    LOG_INFO(pThreadPool->log_fd, LOG_ERROR, "user: %s opreation error: pwd failed", UsrInfo.usr_name);
                    pthread_mutex_unlock(&pThreadPool->mutex);
                    response_msg.type = RESPON_ERROR;
                    response(&response_msg, netfd, "pwd failed!");
                }    
                break;
            case CMD_PUTS:
                printf("cmd_puts\n");
                pthread_mutex_lock(&pThreadPool->mutex);
                LOG_INFO(pThreadPool->log_fd, LOG_OPERATION, "user: %s opreation: puts %s", UsrInfo.usr_name, train.value);
                pthread_mutex_unlock(&pThreadPool->mutex);
                ret = cmd_puts(train.value, &UsrInfo, mysql, netfd);
                if(ret == 0)
                {
                    response(&response_msg, netfd, "finish puts.");
                }
                else
                {
                    printf("puts failed!\n");
                    pthread_mutex_lock(&pThreadPool->mutex);
                    LOG_INFO(pThreadPool->log_fd, LOG_ERROR, "user: %s opreation error: puts %s failed", UsrInfo.usr_name, train.value);
                    pthread_mutex_unlock(&pThreadPool->mutex);
                    response_msg.type = RESPON_ERROR;
                    response(&response_msg, netfd, "puts failed!");
                }
                break;
            case CMD_GETS:
                printf("cmd_gets\n");
                pthread_mutex_lock(&pThreadPool->mutex);
                LOG_INFO(pThreadPool->log_fd, LOG_OPERATION, "user: %s opreation: gets %s", UsrInfo.usr_name, train.value);
                pthread_mutex_unlock(&pThreadPool->mutex);
                ret = cmd_gets(train.value, &UsrInfo, mysql, netfd);
                if(ret == 0)
                {
                    response(&response_msg, netfd, "finish gets.");
                }
                else if(ret == -2)
                {
                    printf("client disconnected!\n");
                    pthread_mutex_lock(&pThreadPool->mutex);
                    LOG_INFO(pThreadPool->log_fd, LOG_OPERATION, "user: %s disconnected while gets %s", UsrInfo.usr_name, train.value);
                    pthread_mutex_unlock(&pThreadPool->mutex);
                }
                else
                {
                    printf("gets failed!\n");
                    response_msg.type = RESPON_ERROR;
                    pthread_mutex_lock(&pThreadPool->mutex);
                    LOG_INFO(pThreadPool->log_fd, LOG_ERROR, "user: %s opreation error: gets %s failed", UsrInfo.usr_name, train.value);
                    pthread_mutex_unlock(&pThreadPool->mutex);
                    response(&response_msg, netfd, "gets failed!");
                }
                break;
            case CMD_MKDIR:
                printf("cmd_mkdir\n");
                printf("train.value : %s\n",train.value);
                pthread_mutex_lock(&pThreadPool->mutex);
                LOG_INFO(pThreadPool->log_fd, LOG_OPERATION, "user: %s opreation: mkdir %s", UsrInfo.usr_name, train.value);
                pthread_mutex_unlock(&pThreadPool->mutex);
                ret = cmd_mkdir(UsrInfo,train.value,mysql,ret_msg,sizeof(ret_msg));
                if(ret == 0)
                {
                    response_msg.type = RESPON_OK;
                    response(&response_msg, netfd, ret_msg);
                    printf("finish mkdir.\n");
                }
                else
                {
                    printf("mkdir failed!\n");
                    pthread_mutex_lock(&pThreadPool->mutex);
                    LOG_INFO(pThreadPool->log_fd, LOG_ERROR, "user: %s opreation error: mkdir %s failed", UsrInfo.usr_name, train.value);
                    pthread_mutex_unlock(&pThreadPool->mutex);
                    response_msg.type = RESPON_ERROR;
                    response(&response_msg, netfd, "mkdir failed!");
                }
                break;
            case CMD_RMDIR:
                printf("cmd_rmdir\n");
                pthread_mutex_lock(&pThreadPool->mutex);
                LOG_INFO(pThreadPool->log_fd, LOG_OPERATION, "user: %s opreation: rmdir %s", UsrInfo.usr_name, train.value);
                pthread_mutex_unlock(&pThreadPool->mutex);
                ret = cmd_rmdir(UsrInfo,train.value,mysql,ret_msg,sizeof(ret_msg));
                if(ret == 0)
                {
                    response_msg.type = RESPON_OK;
                    response(&response_msg, netfd, ret_msg);
                    printf("finish rmdir.\n");
                }
                else
                {
                    printf("rmdir failed!\n");
                    pthread_mutex_lock(&pThreadPool->mutex);
                    LOG_INFO(pThreadPool->log_fd, LOG_ERROR, "user: %s opreation error: rmdir %s failed", UsrInfo.usr_name, train.value);
                    pthread_mutex_unlock(&pThreadPool->mutex);
                    response_msg.type = RESPON_ERROR;
                    response(&response_msg, netfd, "rmdir failed!");
                }
                break;
            case CMD_RM:
                printf("cmd_rm\n");
                pthread_mutex_lock(&pThreadPool->mutex);
                LOG_INFO(pThreadPool->log_fd, LOG_OPERATION, "user: %s opreation: rm %s", UsrInfo.usr_name, train.value);
                pthread_mutex_unlock(&pThreadPool->mutex);
                ret = cmd_rm(&UsrInfo,train.value,mysql,ret_msg,sizeof(ret_msg));
                if(ret == 0)
                {
                    response_msg.type = RESPON_OK;
                    response(&response_msg, netfd, ret_msg);
                    printf("finish rm.\n");
                }
                else
                {
                    printf("rm failed!\n");
                    pthread_mutex_lock(&pThreadPool->mutex);
                    LOG_INFO(pThreadPool->log_fd, LOG_ERROR, "user: %s opreation error: rm %s failed", UsrInfo.usr_name, train.value);
                    pthread_mutex_unlock(&pThreadPool->mutex);
                    response_msg.type = RESPON_ERROR;
                    response(&response_msg, netfd, "rm failed!");
                }
                break;
            case CMD_EXIT:
                printf("cmd_exit\n");
                pthread_mutex_lock(&pThreadPool->mutex);
                LOG_INFO(pThreadPool->log_fd, LOG_OPERATION, "user: %s opreation: exit", UsrInfo.usr_name);
                pthread_mutex_unlock(&pThreadPool->mutex);
                // 对面推出了,不用回应
                break;
            default:
                printf("CMD_UNKNOWN\n");
                pthread_mutex_lock(&pThreadPool->mutex);
                LOG_INFO(pThreadPool->log_fd, LOG_OPERATION, "user: %s opreation: illegal command: %s", UsrInfo.usr_name, train.value);
                pthread_mutex_unlock(&pThreadPool->mutex);
                response_msg.type = RESPON_NONE;
                response(&response_msg, netfd, "CMD_UNKNOWN");
            }
        }
        // business end
        close(netfd);
    }
}

int makeWorker(threadPool_t *pThreadPool)
{
    for (int i = 0; i < pThreadPool->workerInfo.workerNum; ++i)
    {
        pthread_create(&pThreadPool->workerInfo.workerArr[i], NULL, threadWorker, pThreadPool);
    }
    return 0;
}